﻿#pragma once

#include "Misc/CommonMacros.h"

#include <atomic>
#include <cassert>
#include <mutex>

class WHENGINE_API CThreadSafeCounterBase
{
public:
    CThreadSafeCounterBase()
    :Count(1)
    ,WeakCount(0)
    ,Object(nullptr)
    {

    }

    virtual ~CThreadSafeCounterBase()=default;

    std::mutex Locker;
    uint32_t Count;
    uint32_t WeakCount;

    void* Object;
    //std::atomic<bool> bIsDestroyed=false;
    std::atomic<bool> bIsDestroyingObject=false;

    void IncreaseCount()
    {
        std::lock_guard<std::mutex> LockerGuard(Locker);
        assert(Count!=0&& "once object is destroyed,Count should always be zero");
        Count++;
    }

    void DecreaseCount()
    {
        bool ShouldDestroyObject=false;

        {
            std::lock_guard<std::mutex> LockerGuard(Locker);
            Count--;
            ShouldDestroyObject = Count==0 ;
        }

        if(ShouldDestroyObject)
        {
            bIsDestroyingObject.store(true);
            //if the object have weak_this, it will invoke TryDestroy() and delete this
            //, so use bIsDestroyingObject to avoid it
            DestroyObject(); 
            bIsDestroyingObject.store(false);

            TryDestroy();
        }
    }

    void IncreaseWeakCount()
    {
        std::lock_guard<std::mutex> LockerGuard(Locker);
        WeakCount++;
    }

    void DecreaseWeakCount()
    {
        bool ShouldDestroy=false;

        {
            std::lock_guard<std::mutex> LockerGuard(Locker);
            WeakCount--;
            ShouldDestroy = WeakCount==0 && Count==0;
        }

        if(ShouldDestroy)
        {
            TryDestroy();
        }
    }

protected: 
    void TryDestroy()
    {

        //assert(bIsDestroyed.load()==false && "object should not be destroyed twice");

        if(bIsDestroyingObject.load())
        {
            return;
        }

        if(Locker.try_lock())
        {
            bool bShouldDestroy = false;
            //this is not in recursive 
            bShouldDestroy =Count==0 && WeakCount==0;
            
            Locker.unlock();

            if(bShouldDestroy)
            {
                //bIsDestroyed.store(true);
                delete this;
            }
        }
    }

    virtual void DestroyObject() =0;

};

template<typename T>
class CThreadSafeCounter : public CThreadSafeCounterBase
{
public:
    CThreadSafeCounter(T* InObject)
    {
        Object = InObject;
    }

    virtual void DestroyObject() override
    {
        delete static_cast<T*>(Object);
        Object=nullptr;
    }
};

template<typename T>
concept Concept_HasWeakThis = requires(T t)
{
    t._ThreadSafeWeakThis;
};

//thread safe version of std::shared_ptr
template<typename T>
class TThreadSafeSharedPtr
{
public:
    CThreadSafeCounterBase* Counter;

    //object pointer，may different from Counter->Object,
    //beacuse Counter->Object may be derived class object,and this pointer is base class pointer 
    T* Object; 

    std::mutex* CounterLocker=new std::mutex();
public:
    TThreadSafeSharedPtr()
    :Counter(nullptr)
    ,Object(nullptr)
    {

    }

    TThreadSafeSharedPtr(std::nullptr_t)
    :Counter(nullptr)
    ,Object(nullptr)
    {

    }

protected:
    template<typename ObjectType>
    //如果对象有_ThreadSafeWeakThis属性，那么设置它
    requires Concept_HasWeakThis<ObjectType>
    void EnableFromThis(ObjectType* InObject)
    {
        InObject->_ThreadSafeWeakThis = *this;
    }

    template<typename ObjectType>
    //如果对象没有_ThreadSafeWeakThis属性，那么不设置它
    requires (!Concept_HasWeakThis<ObjectType>)
    void EnableFromThis(ObjectType* InObject)
    {
    }

public:

    //裸指针转智能指针
    TThreadSafeSharedPtr(T* InObject)
    :Counter(new CThreadSafeCounter(InObject))
    ,Object(InObject)
    {
        EnableFromThis(InObject);
    }   


    TThreadSafeSharedPtr(CThreadSafeCounterBase* InCounter, T* InObject)
    :Counter(InCounter)
    ,Object(InObject)
    {
        if(Counter)
        {
            Counter->IncreaseCount();
        }
    }

    TThreadSafeSharedPtr(const TThreadSafeSharedPtr<T> & Other)
    // :Counter(Other.Counter)
    // ,Object(Other.Object)
    {
        std::lock_guard<std::mutex> LockerGuard(*Other.CounterLocker);

        Counter = Other.Counter;
        Object = Other.Object;

        if(Counter)
        {
            Counter->IncreaseCount();
        }
    }

    //子类转父类
    template<typename Derived>
    requires std::is_base_of_v<T,Derived>
    TThreadSafeSharedPtr(const TThreadSafeSharedPtr<Derived> & Other)
    {
        std::lock_guard<std::mutex> LockerGuard(*Other.CounterLocker);

        Counter = Other.Counter;
        Object = static_cast<T*>(Other.Object);

        if(Counter)
        {
            Counter->IncreaseCount();
        }
    }

    TThreadSafeSharedPtr(TThreadSafeSharedPtr<T> && Other)
    // :Counter(Other.Counter)
    // ,Object(Other.Object)
    {
        std::lock_guard<std::mutex> LockerGuard(*Other.CounterLocker);

        Counter = Other.Counter;
        Object = Other.Object;

        Other.Counter = nullptr;
        Other.Object = nullptr;
    }

    // template<typename Derived>
    // TThreadSafeSharedPtr(const TThreadSafeSharedPtr<Derived> & Other)
    // :Counter(Other.Counter)
    // ,Object(static_cast<T*>(Other.Object))
    // {
    //     if(Counter)
    //     {
    //         Counter->Counter++;
    //     }
    // }

    // template<typename Derived>
    // TThreadSafeSharedPtr(TThreadSafeSharedPtr<Derived> && Other)
    // :Counter(Other.Counter)
    // ,Object(static_cast<T*>(Other.Object))
    // {
    //     Other.Counter = nullptr;
    //     Other.Object = nullptr;
    // }

    ~TThreadSafeSharedPtr()
    {
        {
            std::lock_guard<std::mutex> LockerGuard(*CounterLocker);
            if(Counter)
            {
                Counter->DecreaseCount();
                
            }
        }

        delete CounterLocker;
    }

    TThreadSafeSharedPtr<T> & operator=(const TThreadSafeSharedPtr<T> & Other)
    {
        std::lock_guard<std::mutex> ThisLock(*this->CounterLocker);

        //check self assigment
        if(this->Counter==Other.Counter)
        {
            return *this;
        }

        if(Counter)
        {
            Counter->DecreaseCount();
            
            Counter=nullptr;
        }
        Object=nullptr;

        std::lock_guard<std::mutex> OtherLock(*Other.CounterLocker);

        Counter = Other.Counter;
        Object = Other.Object;

        if(Counter)
        {
            Counter->IncreaseCount();
        }
        return *this;
    }

    //子类转父类
    template<typename Derived>
    requires std::is_base_of_v<T,Derived>
    TThreadSafeSharedPtr<T> & operator=(const TThreadSafeSharedPtr<Derived> & Other)
    {
        std::lock_guard<std::mutex> ThisLock(*this->CounterLocker);

        //check self assigment
        if(this->Counter==Other.Counter)
        {
            return *this;
        }

        if(Counter)
        {
            Counter->DecreaseCount();
            
            Counter=nullptr;
        }
        Object=nullptr;

        std::lock_guard<std::mutex> OtherLock(*Other.CounterLocker);

        Counter = Other.Counter;
        Object = static_cast<T*>(Other.Object);

        if(Counter)
        {
            Counter->IncreaseCount();
        }
        return *this;
    }

    TThreadSafeSharedPtr<T> & operator=(TThreadSafeSharedPtr<T> && Other)
    {
        std::lock_guard<std::mutex> ThisLock(*this->CounterLocker);

        //check self assigment
        if(this->Counter==Other.Counter)
        {
            return *this;
        }

        if(Counter)
        {
            Counter->DecreaseCount();
            
            Counter=nullptr;
        }
        Object=nullptr;

        std::lock_guard<std::mutex> OtherLock(*Other.CounterLocker);

        Counter = Other.Counter;
        Object = Other.Object;

        Other.Counter=nullptr;
        Other.Object=nullptr;

        return *this;
    }

    bool IsValid() const
    {
        return Counter !=nullptr;
    }


    T* operator->() const
    {
        assert(IsValid());
        return Object;
    }

    T& operator*()
    {
        assert(IsValid());
        return *Object;
    }

    const T& operator*() const
    {
        assert(IsValid());
        return *Object;
    }

    bool operator==(const TThreadSafeSharedPtr<T> & Other) const
    {
        return Counter == Other.Counter;
    }

    bool operator!=(const TThreadSafeSharedPtr<T> & Other) const
    {
        return Counter != Other.Counter;
    }

    bool operator==(const T* Other) const
    {
        return Object == Other;
    }

    bool operator!=(const T* Other) const
    {
        return Object != Other;
    }

    operator bool() const
    {
        return Counter !=nullptr;
    }



    T* Get()
    {
        
        assert(IsValid());
        return Object;
    }

    const T* Get() const
    {
        assert(IsValid());
        return Object;
    }

    void Reset()
    {
        std::lock_guard<std::mutex> ThisLock(*this->CounterLocker);

        if(Counter)
        {
            Counter->DecreaseCount();
        }
        Counter = nullptr;
        Object = nullptr;
    }

    uint64_t GetHashCode() const
    {
        return (uint64_t)Counter;
    }

    

    template<typename T1>
    friend class TThreadSafeWeakPtr;



};


//thread safe version of std::weak_ptr
template<typename T>
class TThreadSafeWeakPtr
{
protected:
    CThreadSafeCounterBase* Counter;
    T* Object;
    std::mutex* CounterLocker=new std::mutex();
public:
    TThreadSafeWeakPtr()
    :Object(nullptr)
    ,Counter(nullptr)
    {

    }

    TThreadSafeWeakPtr(std::nullptr_t)
    :Object(nullptr)
    ,Counter(nullptr)
    {

    }

    TThreadSafeWeakPtr(const TThreadSafeSharedPtr<T> & Other)
    // :Counter(Other.Counter)
    // ,Object(Other.Object)
    {
        std::lock_guard<std::mutex> LockerGuard(*Other.CounterLocker);
    
        Counter = Other.Counter;
        Object = Other.Object;

        if(Counter)
        {
            Counter->IncreaseWeakCount();
        }
    }

    // template<typename Derived>
    // TThreadSafeWeakPtr(const TThreadSafeSharedPtr<Derived> & Other)
    // :Counter(Other.Counter)
    // ,Object(static_cast<T*>(Other.Object))
    // {
    //     if(Counter)
    //     {
    //         Counter->WeakCounter++;
    //     }
    // }

    TThreadSafeWeakPtr(TThreadSafeSharedPtr<T> && Other)
    // :Counter(Other.Counter)
    // ,Object(Other.Object)
    {
        std::lock_guard<std::mutex> LockerGuard(*Other.CounterLocker);

        Counter = Other.Counter;
        Object = Other.Object;

        Other.Counter = nullptr;
        Other.Object = nullptr;

        if(Counter)
        {
            Counter->IncreaseWeakCount();

            Counter->DecreaseCount();
        }

    }

    TThreadSafeWeakPtr(const TThreadSafeWeakPtr<T> & Other)
    // :Counter(Other.Counter)
    // ,Object(Other.Object)
    {
        std::lock_guard<std::mutex> LockerGuard(*Other.CounterLocker);

        Counter = Other.Counter;
        Object = Other.Object;

        if(Counter)
        {
            Counter->IncreaseWeakCount();
        }
    }

    TThreadSafeWeakPtr(TThreadSafeWeakPtr<T> && Other)
    // :Counter(Other.Counter)
    // ,Object(Other.Object)
    {
        std::lock_guard<std::mutex> LockerGuard(*Other.CounterLocker);

        Counter = Other.Counter;
        Object = Other.Object;

        Other.Counter = nullptr;
        Other.Object = nullptr;

    }

    ~TThreadSafeWeakPtr()
    {
        {

            std::lock_guard<std::mutex> LockerGuard(*CounterLocker);

            if(Counter)
            {
                Counter->DecreaseWeakCount();
                
            }
            Counter = nullptr;
            Object = nullptr;
        }
        delete CounterLocker;
    }

    TThreadSafeWeakPtr<T> & operator=(const TThreadSafeSharedPtr<T> & Other)
    {
        std::lock_guard<std::mutex> ThisLock(*this->CounterLocker);

        //check self assigment
        if(this->Counter==Other.Counter)
        {
            return *this;
        }

        if(Counter)
        {
            Counter->DecreaseWeakCount();
            
        }
        Counter=nullptr;
        Object=nullptr;

        std::lock_guard<std::mutex> OtherLock(*Other.CounterLocker);

        Counter = Other.Counter;
        Object = Other.Object;

        if(Counter)
        {
            Counter->IncreaseWeakCount();
        }
        return *this;
    }

    TThreadSafeWeakPtr<T> & operator=(TThreadSafeSharedPtr<T> && Other)
    {
        std::lock_guard<std::mutex> ThisLock(*this->CounterLocker);
        
        if(Counter)
        {
            Counter->DecreaseWeakCount();
            
        }
        Counter=nullptr;
        Object=nullptr;

        std::lock_guard<std::mutex> OtherLock(*Other.CounterLocker);

        Counter = Other.Counter;
        Object = Other.Object;

        Other.Counter=nullptr;
        Other.Object=nullptr;

        if(Counter)
        {
            Counter->IncreaseWeakCount();

            Counter->DecreaseCount();
        }

        return *this;
    }

    template<typename Derived>
    TThreadSafeWeakPtr<T> & operator=(const TThreadSafeSharedPtr<Derived> & Other)
    {
        std::lock_guard<std::mutex> ThisLock(*this->CounterLocker);

        //check self assigment
        if(this->Counter==Other.Counter)
        {
            return *this;
        }

        if(Counter)
        {
            Counter->DecreaseWeakCount();
            
        }
        Counter=nullptr;
        Object=nullptr;

        std::lock_guard<std::mutex> OtherLock(*Other.CounterLocker);

        Counter = Other.Counter;
        Object = static_cast<T*>(Other.Object);

        if(Counter)
        {
            Counter->IncreaseWeakCount();
        }
        return *this;
    }

    TThreadSafeWeakPtr<T> & operator=(const TThreadSafeWeakPtr<T> & Other)
    {
        std::lock_guard<std::mutex> ThisLock(*this->CounterLocker);

        //check self assigment
        if(this->Counter==Other.Counter)
        {
            return *this;
        }

        if(Counter)
        {
            Counter->DecreaseWeakCount();
            
        }
        Counter=nullptr;
        Object=nullptr;

        std::lock_guard<std::mutex> OtherLock(*Other.CounterLocker);

        Counter = Other.Counter;
        Object = Other.Object;

        if(Counter)
        {
            Counter->IncreaseWeakCount();
        }
        return *this;
    }

    TThreadSafeWeakPtr<T> & operator=(TThreadSafeWeakPtr<T> && Other)
    {
        std::lock_guard<std::mutex> ThisLock(*this->CounterLocker);

        //check self assigment
        if(this->Counter==Other.Counter)
        {
            return *this;
        }

        if(Counter)
        {
            Counter->DecreaseWeakCount();
            
        }
        Counter=nullptr;
        Object=nullptr;

        std::lock_guard<std::mutex> OtherLock(*Other.CounterLocker);

        Counter = Other.Counter;
        Object = Other.Object;

        Other.Counter=nullptr;
        Other.Object=nullptr;

        return *this;
    }

    bool operator==(const TThreadSafeWeakPtr<T> & Other) const
    {
        return Counter == Other.Counter;
    }

    bool operator!=(const TThreadSafeWeakPtr<T> & Other) const
    {
        return Counter != Other.Counter;
    }

    bool operator==(const T* Other) const
    {
        if(Other==nullptr)
        {
            return Counter == nullptr || Counter->Count==0 ;
        }
        else
        {
            return Object == Other && Counter && Counter->Count>0 ;
        }

    }

    bool operator!=(const T* Other) const
    {
        if(Other==nullptr)
        {
            return Counter != nullptr && Counter->Count>0 ;
        }
        else
        {
             return Object != Other || Counter==nullptr || Counter->Count==0 ;
        }
    }

    operator bool() const
    {
        return Counter !=nullptr && Counter->Count>0;
    }

    bool IsValid() const
    {
        
        return Counter !=nullptr && Counter->Count>0;
    }

    TThreadSafeSharedPtr<T> Lock() 
    {
        std::lock_guard<std::mutex> LockerGuard(*CounterLocker);
        if(!Counter)
        {
            return TThreadSafeSharedPtr<T>();
        }

        std::lock_guard<std::mutex> LockerGuard2(Counter->Locker);
        if(Counter->Count>0)
        {
            TThreadSafeSharedPtr<T> SharedPtr;
            SharedPtr.Counter = Counter;
            SharedPtr.Object = Object;
            Counter->Count++;
            return SharedPtr;
        }
        return TThreadSafeSharedPtr<T>();
    }
};


template<typename T>
class EnableThreadSafeSharedPtrFromThis
{

public:
    TThreadSafeWeakPtr<T> _ThreadSafeWeakThis; 
    using _EnabledThreadSafeSharedPtrFromThis = EnableThreadSafeSharedPtrFromThis;
protected:
    TThreadSafeSharedPtr<T> AsShared()
    {
        assert(_ThreadSafeWeakThis.IsValid() && "Must create object with MakeThreadSafeSharedPtr()" );
        return _ThreadSafeWeakThis.Lock();
    }
};


namespace WH
{
    template<typename T,typename ...Args >
    TThreadSafeSharedPtr<T> MakeThreadSafeSharedPtr(Args&& ... args)
    {
        return TThreadSafeSharedPtr<T>(new T(std::forward<Args>(args)...));
    }

    //转换TThreadSafeSharedPtr<T>为TThreadSafeSharedPtr<U>
    template<typename T,typename U>
    TThreadSafeSharedPtr<T> StaticCastThreadSafeSharedPtr(const TThreadSafeSharedPtr<U> & InPtr)
    {
        return TThreadSafeSharedPtr<T>(InPtr.Counter,static_cast<T*>(InPtr.Object));
    }

    //convert TThreadSafeSharedPtr<T> to TThreadSafeSharedPtr<T2>
    template<typename T,typename T2>
    TThreadSafeSharedPtr<T2> StaticCastThreadSafeSharedPtr(const TThreadSafeSharedPtr<T> & InPtr)
    {
        return TThreadSafeSharedPtr<T2>(InPtr.Counter,static_cast<T2*>(InPtr.Object));
    }


}